import { Resolve, Reject, Status, Then, Fn, PromiseLike, FulfilledFn, RejectedFn } from './type.js'

/**手撕promise */
class myPromise<T>{
    /**当前promise的状态 */
    status: Status = Status.Pending
    /**成功后的值 */
    #value!: T
    /**失败后的原因 */
    #reason: any
    //下面这两个队列使用观察者模式
    /**成功回调的等待队列 */
    #fulfilledList: Fn[] = []
    /**拒绝回调的等待队列 */
    #rejectedList: Fn[] = []

    constructor(fn: (resolve: Resolve<T>, reject: Reject) => void) {
        fn.call(this, this.#resolve, this.#reject)
    }
    //函数都使用箭头函数，this就是本class了
    /**resolve函数
     * @param data 要给then的data
     */
    #resolve: Resolve<T> = (data) => {
        if (this.status === Status.Pending) {//只有等待态才能变成完成态
            this.status = Status.Fulfilled
            this.#value = data!
            this.#fulfilledList.forEach(onFulfilled => onFulfilled())//把等待队列中的全部取出来执行 
        }
    }
    /**reject函数
     * @param error 要给catch的错误信息
     */
    #reject: Reject = (error) => {
        if (this.status === Status.Pending) {//只有等待态才能变成拒绝态
            this.status = Status.Rejected
            this.#reason = error
            this.#rejectedList.forEach(onRejected => onRejected()) //把等待队列中的全部取出来执行  
        }
    }
    /**then函数
     * @param onFulfilled 成功回调
     * @param onRejected 失败回调
     */
    then = <U>(onFulfilled?: FulfilledFn<T>, onRejected?: RejectedFn) => {
        /**返回给下一个的链式调用的promise */
        const promise2 = new myPromise<U>((resolve2, reject2) => {
            //把两个回调抽离在这里，方便异步情况下能够执行相同的操作
            /**成功回调 */
            const fulfilledFn = () => {
                const res = onFulfilled && onFulfilled(this.#value)
                resolvePromise(res, resolve2, reject2)
            }
            /**拒绝回调 */
            const rejectFn = () => {
                const res = onRejected && onRejected(this.#reason)
                resolvePromise(res, resolve2, reject2)
            }

            if (this.status === Status.Fulfilled) {
                fulfilledFn()
            } else if (this.status === Status.Rejected) {
                rejectFn()
            } else {//如果是pending状态，那就把这俩函数放进回调队列中，等resolve或reject的时候拿出来执行
                this.#fulfilledList.push(fulfilledFn)
                this.#rejectedList.push(rejectFn)
            }
        })
        return promise2
    }
}
export default myPromise

/**根据不同的返回值，修改promise2的状态
 * @param value 返回值
 * @param resolve promise2的resolve函数
 * @param reject promise2的reject函数 
 */
function resolvePromise(value: any, resolve: Resolve<any>, reject: Reject) {
    if (typeof value === "object" || typeof value === "function") {
        if (value === null) {
            // 如果返回值是 null，直接调用resolve函数，让promise2 的状态变为 fulfilled，返回值由下一个 then 方法的第一个回调函数接收。 
            return resolve(value);
        }
        try {
            if (typeof value.then === "function") {
                // 如果返回值是 Promise 对象或者 thenable 对象，那就交给它们的 then 方法来改变 promise2 的状态，以及获取相对应的状态值 
                value.then(resolve, reject);
            } else {
                // 如果 then 不是函数，就直接返回原数据。
                resolve(value);
            }
        } catch (error) {
            // 出现异常的情况下，调用 reject 函数，promise2 的状态变为 rejected，错误信息由下一个 then 方法的第二回调函数接收 
            reject(error);
        }
    } else {
        // 如果返回值是其他普通对象或者原始数据类型值，直接resolve 
        resolve(value);
    }
} 